import org.junit.Test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.SortedMap;

/**
 * @program: nio-learning
 * @description: 通道测试类
 * @author: zhaoxianglong
 * @create: 2021-03-08 15:04
 * @other Channel : 通道,用于连接起始节点和目标节点,负责数据的传输, 本身不存储任何数据, 在nio中和缓冲区(Buffer)配套使用
 *        主要子类有: FileChannel, SocketChannel, ServerSocketChannel, DatagramChannel
 *
 * @other 获取通道有如下方法:
 *           通过支持通道的类中的getChannel()方法: 如FileInputStream,FileOutputStream,RandomAccessFile,Socket,ServerSocket,DatagramSocket......
 *           Channel中的静态方法open()
 *           Files工具类的newByteChannel()
 **/
public class ChannelTest {

    /**
     * 利用第一种获取通道方法进行数据复制测试
     * 非直接缓冲区
     * @throws Exception
     */
    @Test
    public void test1() throws Exception{
        /*
        创建输入输出流
         */
        FileInputStream fileInputStream = new FileInputStream("1.jpg");
        FileOutputStream fileOutputStream = new FileOutputStream("2.jpg");

        /*
        获取通道
         */
        FileChannel inputStreamChannel = fileInputStream.getChannel();
        FileChannel outputStreamChannel = fileOutputStream.getChannel();

        /*
        建立缓冲区
         */
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        //如果没到末尾则继续读
        while (inputStreamChannel.read(byteBuffer) != -1) {
            //切换缓冲区到读模式
            byteBuffer.flip();
            //写出文件
            outputStreamChannel.write(byteBuffer);
            //清空缓冲区
            byteBuffer.clear();
        }

        //关闭流
        inputStreamChannel.close();
        outputStreamChannel.close();
        fileInputStream.close();
        fileOutputStream.close();
    }


    /**
     * 使用直接内存区进行复制
     * @throws IOException
     */
    @Test
    public void test2() throws IOException {
        //创建通道
        FileChannel read = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
        FileChannel write = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE , StandardOpenOption.READ);

        //内存映射文件
        MappedByteBuffer readBuffer = read.map(FileChannel.MapMode.READ_ONLY, 0, read.size());
        MappedByteBuffer writeBuffer = write.map(FileChannel.MapMode.READ_WRITE, 0, read.size());

        //对缓冲区进行读写
        byte[] bytes = new byte[readBuffer.limit()];
        readBuffer.get(bytes);
        writeBuffer.put(bytes);

        read.close();
        write.close();
    }

    /**
     * 使用通道直接进行数据传输(直接缓冲区)
     * @throws IOException
     */
    @Test
    public void test3() throws IOException {
        //创建通道
        FileChannel read = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
        FileChannel write = FileChannel.open(Paths.get("4.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE , StandardOpenOption.READ);

//        read.transferTo(0 , read.size() , write);
        write.transferFrom(read , 0 , read.size());

        read.close();
        write.close();
    }

    /**
     * 分散读取和聚集写入
     * @throws IOException
     */
    @Test
    public void test4() throws IOException {
        //创建通道
        FileChannel read = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
        FileChannel write = FileChannel.open(Paths.get("5.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE , StandardOpenOption.READ);

        ByteBuffer byteBuffer1 = ByteBuffer.allocate(100);
        ByteBuffer byteBuffer2 = ByteBuffer.allocate(1024);

        ByteBuffer[] byteBuffers = {byteBuffer1 , byteBuffer2};

        read.read(byteBuffers);

        write.write(byteBuffers);
    }

    /**
     * 查看字符集
     */
    @Test
    public void test5(){
        SortedMap<String, Charset> charsets = Charset.availableCharsets();
        charsets.forEach((str , sets) -> {
            System.out.println(str + "=" + sets);
        });
    }
}
